package com.cmall.common.foundation.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 微服务请求
 */
public class HttpClientUtils {

	private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);

    public static String KEY = "";
    //请求方式
    public static String GET = "get";
    public static String PUT = "put";
    public static String POST = "post";


    public static Random random = new Random();

    /**
     * 通过get请求，获取数据
     *
     * @param url
     * @return
     */
    private static String get(String url, Map<String, String> params) {
        HttpClient httpClient = new HttpClient();
        GetMethod getMethod = new GetMethod(url);
        //添加签名验证
        Map<String, String> signParamsMap = getSignParamsMap(url);
        for (Map.Entry<String, String> entry : signParamsMap.entrySet()) {
            getMethod.setRequestHeader(entry.getKey(), entry.getValue());
        }
        getMethod.setRequestHeader("Content-Type", "charset=utf-8");
        int statusCode = 0;
        try {
            statusCode = httpClient.executeMethod(getMethod);
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage(),e);
        }
        if (statusCode != HttpStatus.SC_OK) {
            throw new RuntimeException("http request error" + statusCode);
        }

        String responseBodyAsString = null;
        try {
            responseBodyAsString = getMethod.getResponseBodyAsString();
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage(),e);
        }
        return responseBodyAsString;

    }

    /**
     * 获取请求信息
     *
     * @param url
     * @return JSONObject
     */
    public static JSONObject getHttpResponse(String url, Map<String, String> params, String requestType) {
        JSONObject response = null;
        if (url == null || url.equals("")) {
            return null;
        }
        try {
            String resp = "";
            if (requestType.equals(GET)) {
                resp = get(url, params);
            } else if (requestType.equals(PUT)) {
                resp = put(url, params);
            }
            JSONObject data = JSONObject.parseObject(resp);
            String status = data.getString("status");
            if (StringUtil.isEmpty(status) || !"0".equalsIgnoreCase(status)) {
                return null;
            }
            response = data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 通过get请求，获取数据
     *
     * @param url
     * @return
     */
    @SuppressWarnings("deprecation")
	private static String put(String url, Map<String, String> params) {
        HttpClient httpClient = new HttpClient();
        PutMethod putMethod = new PutMethod(url);
        putMethod.addRequestHeader("Content-Type", "application/json");
        HttpMethodParams httpParams = putMethod.getParams();
        if (params != null) {
            String jsonString = JSON.toJSONString(params);
            putMethod.setRequestBody(jsonString);
            for (Map.Entry<String, String> entry : params.entrySet()) {
                httpParams.setParameter(entry.getKey(), entry.getValue());
            }
        }
        //添加签名验证
        Map<String, String> signParamsMap = getSignParamsMap(url);
        for (Map.Entry<String, String> entry : signParamsMap.entrySet()) {
            httpParams.setParameter(entry.getKey(), entry.getValue());
        }
        int statusCode = 0;
        try {
            statusCode = httpClient.executeMethod(putMethod);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (statusCode != HttpStatus.SC_OK) {
            throw new RuntimeException("http request error" + statusCode);
        }
        String responseBodyAsString = null;
        try {
            responseBodyAsString = putMethod.getResponseBodyAsString();
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage(),e);
        }
        return responseBodyAsString;
    }

    /**
     * 生成签名
     *
     * @param url
     * @return
     */
    private static Map<String, String> getSignParamsMap(String url) {
        Map<String, String> map = new HashMap<String, String>();
        long time = new Date().getTime();
        int randomInt = random.nextInt(Integer.MAX_VALUE);
        String path = "";
        String queryString = "";
        try {
            URL netUrl = new URL(url);
            path = netUrl.getPath();
            queryString = netUrl.getQuery();
            if (queryString == null) {
                queryString = "";
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        String sign = MD5Util.md5(randomInt + String.valueOf(time) + path + "?" + queryString + KEY);
//        map.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        map.put("X_Timestamp", String.valueOf(time));
        map.put("X_Nonce", String.valueOf(randomInt));
        map.put("X_Sign", sign);
        return map;
    }
    /**
     * 不带加密请求
     * 
     */
	public static String doPost(String url, Map<String,Object> param){  
    	PrintWriter out = null;
		BufferedReader in = null;
		String result = "";
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();
			// 设置通用的请求属性
			//conn.setRequestProperty("Accept-Charset", "utf-8");
			conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
			conn.setRequestProperty("Accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			//conn.setRequestProperty("User-Agent", "PostmanRuntime/6.4.1");
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			// 获取URLConnection对象对应的输出流
			out = new PrintWriter(conn.getOutputStream());
			// 发送请求参数
			out.print(JSONObject.toJSONString(param));
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应
			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			System.out.println("发送 POST 请求出现异常！" + e);
			e.printStackTrace();
		}
		// 使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return result;
    }
    /**
     * 不帶加密的get请求，获取数据
     *
     * @param url
     * @return
     */
    public static String doGet(String url, Map<String, String> params) {
        HttpClient httpClient = new HttpClient();
        GetMethod getMethod = new GetMethod(url);

        getMethod.setRequestHeader("Content-Type", "charset=utf-8");
        int statusCode = 0;
        try {
            statusCode = httpClient.executeMethod(getMethod);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (statusCode != HttpStatus.SC_OK) {
            throw new RuntimeException("http request error" + statusCode);
        }

        String responseBodyAsString = null;
        try {
            responseBodyAsString = getMethod.getResponseBodyAsString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return responseBodyAsString;
    }

    /**
     * @param url
     * @param params get请求参数 地址栏拼接
     */
    public static String getWithParams(String url, Map<String, String> params) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            URIBuilder builder = new URIBuilder(url);
            if (params != null) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    builder.setParameter(entry.getKey(), entry.getValue());
                }
            }
            HttpGet httpGet = new HttpGet(builder.build());
            //添加签名验证
            Map<String, String> signParamsMap = getSignParamsMap(builder.toString());
            for (Map.Entry<String, String> entry : signParamsMap.entrySet()) {
                httpGet.addHeader(entry.getKey(), entry.getValue());
            }
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                throw new RuntimeException("http request error" + statusCode);
            }
            String result = EntityUtils.toString(response.getEntity());
            return result;
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }finally {
            try {
                httpClient.close();//释放资源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
	/**
	 * 带加密请求
	 * @param requestUrl
	 * @param param
	 * @return
	 */
	public static String httpPostJsonBody(String requestUrl, Map<String,Object> param) {
        String result = "";
        BufferedReader in = null;
        PrintWriter out = null;
        try {
            // Configure and open a connection to the site you will send the
            String jsonStr = JSONObject.toJSONString(param);
        	URL url = new URL(requestUrl);
            String nonce = HttpClientUtils.getNonce();
            System.out.println("nonce --->" +nonce);

            String timestamp = HttpClientUtils.getTimestamp();
            System.out.println("timestamp --->" +timestamp);

            String sign = HttpClientUtils.getSign(nonce, timestamp, null, null, jsonStr);
            System.out.println("sign --->" +sign);

            URLConnection urlConnection = url.openConnection();
            // 设置doOutput属性为true表示将使用此urlConnection写入数据
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            // 设置超时时间
            //urlConnection.setConnectTimeout(60);
            // 定义待写入数据的内容类型，我们设置为application/x-www-form-urlencoded类型
            // "content-type=application/json","content-type=application/xml"
            urlConnection.setRequestProperty("content-type", "application/json");
            //设置签名相关
            urlConnection.setRequestProperty("X_Timestamp", timestamp);
            urlConnection.setRequestProperty("X_Nonce", nonce);
            urlConnection.setRequestProperty("X_Sign", sign);
            //urlConnection.setRequestProperty();
            // 得到请求的输出流对象
            out = new PrintWriter(urlConnection.getOutputStream());
            // 把数据写入请求的Body
            // 获取jsonStr
            if (StringUtils.isNotBlank(jsonStr)){
                out.write(jsonStr);
        	}else{
                out.write("");
        	}
            out.flush();
            out.close();
            // 从服务器读取响应
            in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "utf-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
        	try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
        }
        return result;
    }
    @SuppressWarnings({ "rawtypes", "unchecked" })
   	public static String post(String url, Map map){  
       	CloseableHttpClient httpClient = null;
           HttpPost httpPost = null;
           String result = null;
           String charset = "UTF-8";
           try{
               httpClient = HttpClients.createDefault();
               httpPost = new HttpPost(url);
               //设置参数
               List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
               Iterator iterator = map.entrySet().iterator();
               while(iterator.hasNext()){
                   Map.Entry<String,String> elem = (Map.Entry<String, String>) iterator.next();
                   list.add(new BasicNameValuePair(elem.getKey(),elem.getValue()));
               }
               if(list.size() > 0){
                   UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,charset);
                   httpPost.setEntity(entity);
               }
               HttpResponse response = httpClient.execute(httpPost);
               if(response != null){
                   HttpEntity resEntity = response.getEntity();
                   if(resEntity != null){
                       result = EntityUtils.toString(resEntity,charset);
                   }
               }
           }catch(Exception ex){
               ex.printStackTrace();
               logger.error(ex.getMessage());
               return result;
           }
           return result;
       }


    /**
     * httpPost maps 请求
     * param url 地址
     * param params 参数
     * param encode 编码
     */
    public static String urlPost(String url, Map<String,Object> params,String encode) {
        OutputStream out = null;
        String result = "";
        try
        {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            HttpURLConnection conn = (HttpURLConnection) realUrl
                    .openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            conn.setRequestProperty("charset", "utf-8");
            conn.setUseCaches(false);
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setReadTimeout(5000);
            conn.setConnectTimeout(5000);
            StringBuffer stringBuffer = new StringBuffer();
            if (params != null && !params.isEmpty())
            {
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    try {
                        stringBuffer
                                .append(entry.getKey())
                                .append("=")
                                .append(URLEncoder.encode(entry.getValue().toString(), encode))
                                .append("&");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
                stringBuffer.deleteCharAt(stringBuffer.length() - 1);

                byte[] mydata = stringBuffer.toString().getBytes();
                // 获取URLConnection对象对应的输出流
                out = conn.getOutputStream();
                // 发送请求参数
                out.write(mydata);
                // flush输出流的缓冲
                out.flush();
                int responseCode  = conn.getResponseCode();//获取服务器响应状态码
                if(responseCode==200){
                    // 获得输入流，从服务器端获得数据
                    InputStream inputStream = conn.getInputStream();
                    return (changeInputStream(inputStream,encode));
                }
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                }
            } catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
        return result;
    }


    private static String changeInputStream(InputStream inputStream,
                                            String encode) {
        ByteArrayOutputStream  arrayOutputStream = new ByteArrayOutputStream();
        byte[] data = new byte[1024];
        int len =0;
        String result ="";
        if(inputStream!=null){
            try{
                while((len =inputStream.read(data))!=-1){
                    arrayOutputStream.write(data,0,len);
                }
                result  = new String(arrayOutputStream.toByteArray(),encode);//按照编码读取服务器数据
            }catch(Exception e){

            }
        }
        return result;
    }
    /**
     * 获取时间戳
     *
     * @return
     */
    private static String getTimestamp() {
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     * 获取随机字符串
     *
     * @return
     */
    private static String getNonce() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 10);
    }
    /**
     * 获取签名
     *
     * @param nonce
     * @param timestamp
     * @param uri
     * @param queryString
     * @param requestBody
     * @return
     */
    private static String getSign(String nonce, String timestamp, String uri, String queryString, String requestBody) {
        String signStr = null;
        if (StringUtils.isBlank(requestBody)) {
            //System.out.println(StringUtils.isBlank(queryString) );
            signStr = nonce + timestamp + uri + "?" + (StringUtils.isBlank(queryString) || "null".equals(queryString)?"":queryString )+ "{" + KEY + "}";
        } else {
            signStr = nonce + timestamp + requestBody + KEY;
        }
        System.out.println("signStr --->" +signStr);
        if (StringUtils.isNotBlank(signStr)) {
            return MD5Util.md5(signStr);
        }
        return null;
    }
}
